package com.examination.client.util;

import com.google.common.base.Joiner;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.util.List;

import static com.examination.client.util.IOUtils.*;

/**
 * Created by liangtao on 2020/1/17
 * 提供http/https请求的便捷方法 并忽略证书
 */
public class HttpUtil {

    private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);

    /**
     * 发送POST请求，并获得返回结果
     *
     */
    public static String send(String requestUrl, String method, String data, String encoding, String contentType) {

        String result = null;
        HttpURLConnection conn = null;
        PrintStream out = null;
        InputStream in = null;

        try {
            //1:获得http连接并设置连接参数
            URL url =  new URL(requestUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(15 * 1000);
            conn.setReadTimeout(15 * 1000);
            conn.setUseCaches(false);
            conn.setRequestMethod(method);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestProperty("Content-type", contentType);
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Accept-Charset", encoding);
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            if ("https".equalsIgnoreCase(url.getProtocol())) {
                ((HttpsURLConnection) conn).setHostnameVerifier((hostname, session) -> true);
                ((HttpsURLConnection) conn).setSSLSocketFactory(new BaseHttpSSLSocketFactory());
            }

            //2:发送请求数据
            out = new PrintStream(conn.getOutputStream(), false, encoding);
            IOUtils.write(data, out, encoding);

            //3:获得响应数据
            in = (200 == conn.getResponseCode()) ? conn.getInputStream() : conn.getErrorStream();
            List<String> resultList = IOUtils.readLines(in, encoding);
            result = Joiner.on("").join(resultList);
        } catch (Exception e) {
            logger.error("请求异常:", e);
        } finally {
            closeOutputStream(out);
            closeInputStream(in);
            closeUrlConnection(conn);
        }
        return result;
    }

    /**
     * 发送 https 请求.
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式（GET、POST）
     * @param outputStr     提交的数据
     * @return json字符串
     */
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        try {
            // 创建 SSLContext 对象，并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述 SSLContext 对象中得到 SSLSocketFactory 对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);

            // 设置请求方式（GET/POST）
            conn.setRequestMethod(requestMethod);

            // 当 outputStr 不为 null 时，向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();

                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();

            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }

            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            logger.error(" 连接超时：", ce);
        } catch (Exception exc) {
            exc.printStackTrace();
            logger.error("https 请求异常：", exc);
        }
        return "";
    }

    /**
     * 带证书发送请求
     * @param url   请求url
     * @param data  请求数据
     * @param cer   证书
     * @param mchId （微信）商户号
     * @param host  host地址
     * @param isAppendReturn  是否追加换行符
     * @return 结果
     */
    @SuppressWarnings({ "unused", "deprecation" })
    public static String ssl(String url, String data, File cer, String mchId, String host, boolean isAppendReturn){
        StringBuilder message = new StringBuilder();
        try {
            KeyStore keyStore  = KeyStore.getInstance("PKCS12");

            //服务器上的证书
            URL urlb = new URL(url);
            URLConnection conn = urlb.openConnection();
            //请求服务器是证书方式
            // http的连接类
            HttpURLConnection httpURLConnection = (HttpURLConnection) conn;
            // 设定请求的方法，默认是GET
            httpURLConnection.setRequestMethod("POST");
            // 设置字符编码
            httpURLConnection.setRequestProperty("Charset", "UTF-8");
            // 打开到此 URL 引用的资源的通信链接（如果尚未建立这样的连接）。
            httpURLConnection.connect();

            //本地请求证书使用
	        FileInputStream instream = new FileInputStream(cer);
            keyStore.load(instream, mchId.toCharArray());
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            HttpPost httpost = new HttpPost(url);
            httpost.addHeader("Connection", "keep-alive");
            httpost.addHeader("Accept", "*/*");
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpost.addHeader("Host", host);
            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpost.addHeader("Cache-Control", "max-age=0");
            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), StandardCharsets.UTF_8));
                    String text;
                    while ((text = bufferedReader.readLine()) != null) {
                        message.append(text).append(isAppendReturn ? "\r" : "");
                    }
                }
                EntityUtils.consume(entity);
            } catch (IOException e) {
               logger.error("ssl error:", e);
            } finally {
                response.close();
            }
        } catch (Exception e1) {
            logger.error("ssl error:", e1);
        }

        return message.toString();
    }

    /**
     *
     * @param url 下载地址
     * @param date 以日期为格式的路径
     * @param dirName 以交易类型为格式的路径
     * @param suffix 后缀
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static File getFileFromUrl(String url, String date, String dirName, String suffix) throws ClientProtocolException, IOException {
        String tempPath =  String.format("%s%s%s", "/", dirName , "/");
        String fileName =  String.format("%s%s", date, suffix);

        //1,导包
        //2,得到HttpClient对象
        HttpClient client =  HttpClients.createDefault();

        //3,设置请求方式
        HttpGet get = new HttpGet(url);

        //4,执行请求, 获取响应信息
        HttpResponse response = client.execute(get);

        if(response.getStatusLine().getStatusCode() == 200)
        {
            //得到实体
            HttpEntity entity = response.getEntity();

            byte[] data = EntityUtils.toByteArray(entity);

            File tempFile = new File(tempPath);

            if(!tempFile.exists()){
                tempFile.mkdirs();
            }
            tempPath += fileName;
            //存入磁盘
            FileOutputStream fos = new FileOutputStream(tempPath);
            fos.write(data);
            fos.close();
            logger.info(String.format("%s-%s，%s", dirName, date, "文件下载成功!!!!"));
        }
        File tempFile = new File(tempPath);
        if(tempFile.exists()){
            return tempFile;
        }
        return null;
    }
}
